﻿using System;                                                                           //TODO: validate, DateTime, Edit, поубирать File (заменить на getPatient)
using System.Collections.Generic;                                                        // fix:Prints Patient deleted when Patient is not found at all
using System.Collections;                                                              // method to delete all text from File
using System.Linq;
using System.Text;
using System.IO;
using System.Globalization;

namespace ConsoleApplication1
{
    class PatientDB
    {
        static string PATH = ".//..//..//patient.dbf";

        static void Main(string[] args)
        {
            bool valid = ValidateArgs(args);
            if (valid == false)
            {
                PrintHelp();
                return;
            }
            string command = args[0].Substring(1);

            if (command == "add")
            {
                Patient pNew = ParseFieldsCurPatient(args);
                ArrayList lines = GetPatients();
                int newId = GetNewId(lines);
                pNew.id = newId;
                SavePatientToDB(pNew, lines);

                Console.WriteLine("Patient added. New patient ID: " + newId);
            }
            else if (command == "edit")
            {
                Patient pNew = ParseFieldsCurPatient(args);
                ArrayList lines = GetPatients();
                Patient newPatient = CompareNewOld(pNew, lines);
                SavePatientToDB(newPatient, lines);

                Console.WriteLine("Patient with id " + pNew.id + " edited");
            }
            else if (command == "delete")
            {
                Patient pToDel = ParseFieldsCurPatient(args);
                bool ifDeleted = DeletePatient(pToDel);
                if (ifDeleted)
                {
                    Console.WriteLine("Patient ID:" + pToDel.id + " deleted ");
                }
                else
                {
                    Console.WriteLine("Patient with ID:" + pToDel.id + " not found");
                }
                Console.WriteLine();
            }

            else if (command == "list")
            {
                ArrayList res = GetPatients();
                string[] headLines = { "id", "name", "surname", "patronymic", "date of birth" };
                SetColumnWidth(headLines);
                Console.WriteLine();
                PrintPatients(res);
                Console.WriteLine();
            }
        }

        static public void PrintHelp()
        {
            Console.WriteLine("HELP");
            Console.WriteLine();
            Console.WriteLine("Enter valid command:");
            Console.WriteLine("To add a patient: -add -name:Ivan -surname:Ivanov -patronymic:Ivanovich -dob:10-dec-2014");
            Console.WriteLine("To delete a patient: -delete -id:10");
            Console.WriteLine("To edit a patient: -edit -id:11 -name:Ivan -surname:Ivanov");
            Console.WriteLine("To list patients: -list");
        }


        public static Patient ParseFieldsCurPatient(string[] args)
        {                                                             // убрать всю валидацию
            string[] curPatient = new string[5];

            for (int i = 1; i < args.Length; i++)
            {
                string field = args[i].Substring(0);
                if (field.StartsWith("-id:"))
                {
                    string ID = args[i].Substring(4);
                    curPatient[0] = ID;
                }
                else if (field.StartsWith("-name:"))
                {
                    string name = args[i].Substring(6);
                    curPatient[1] = name;
                }
                else if (field.StartsWith("-surname:"))
                {
                    string surname = args[i].Substring(9);
                    curPatient[2] = surname;
                }
                else if (field.StartsWith("-patronymic:"))
                {
                    string patronymic = args[i].Substring(12);
                    curPatient[3] = patronymic;
                }
                else if (field.StartsWith("-dob:"))
                {
                    string dob = args[i].Substring(5);
                    DateTime dt;
                    if (DateTime.TryParseExact(dob, "dd-MM-yyyy", null, DateTimeStyles.None, out dt))
                    {
                        curPatient[4] = dt.ToString("dd-MM-yyyy");
                    }
                    else
                    {
                        PrintHelp();
                        return null;
                    }
                }
                else
                {
                    return null;
                }
            }

            return Patient.parseFromStringArray(curPatient);
        }


        static public ArrayList GetPatients()
        {
            ArrayList lines = new ArrayList(File.ReadAllLines(PATH));
            ArrayList res = new ArrayList();

            foreach (var elem in lines)
            {
                Patient p = Patient.parseFromDb((string)elem);
                res.Add(p);
            }

            return res;
        }

        public static int GetNewId(ArrayList lines)
        {
            int newId;
            if (lines.Count > 0)
            {
                Patient lastPat = (Patient)lines[lines.Count - 1];
                newId = lastPat.id + 1;
            }
            else
            {
                newId = 1;
            }
            return newId;
        }

        public static Patient CompareNewOld(Patient pNew, ArrayList lines)
        {
            Patient curPat = null;
            foreach (var elem in lines)
            {
                curPat = (Patient)elem;

                if (curPat.id == pNew.id)
                {
                    if (pNew.name != null)
                    {
                        curPat.name = pNew.name;
                    }
                    if (pNew.surname != null)
                    {
                        curPat.surname = pNew.surname;
                    }
                    if (pNew.patronymic != null)
                    {
                        curPat.patronymic = pNew.patronymic;
                    }
                    if (pNew.dob != null && pNew.dob != DateTime.MinValue)
                    {
                        curPat.dob = pNew.dob;
                    }
                    break;
                }
            }
            return curPat;
        }

        public static void SavePatientToDB(Patient pNew, ArrayList lines)
        {
            File.WriteAllText(PATH, "");

            Patient curPat;
            bool patientFound = false;
            int i = 0;

            while (i < lines.Count)
            {
                curPat = (Patient)lines[i];
                if (curPat.id == pNew.id)
                {
                    File.AppendAllText(PATH, pNew.toDbFormat() + Environment.NewLine);
                    patientFound = true;
                    i++;
                }
                else
                {
                    File.AppendAllText(PATH, curPat.toDbFormat() + Environment.NewLine);
                    i++;
                }
            }
            if (patientFound == false)
            {
                File.AppendAllText(PATH, pNew.toDbFormat() + Environment.NewLine);
            }

        }


        public static bool DeletePatient(Patient pToDel)
        {
            ArrayList res = GetPatients();
            File.WriteAllText(PATH, "");
            bool ifDeleted = false;
            foreach (var elem in res)
            {
                Patient p = (Patient)elem;
                if (p.id != pToDel.id)
                {
                    File.AppendAllText(PATH, p.toDbFormat() + Environment.NewLine);
                }
                else
                {
                    ifDeleted = true;
                }
            }
            return ifDeleted;
        }


         static public bool TryParseID(string id)
        {
            bool valid = false;
            int number;
            if (Int32.TryParse(id, out number) == true)
            {
                valid = true;
            }
            return valid;
        }

        static public bool ValidateArgs(string[] args)
        {
            bool valid = false;
            if (args.Length != 0)
            {
                if (args[0] == "-add")
                {
                    if (CheckDuplicates(args))
                    {
                        return false;
                    }
                    if (args.Length > 1 && args.Length <= 5)
                    {
                        for (int i = 1; i < args.Length; i++)
                        {
                            if (args[i].StartsWith("-name:") && args[i].Substring(6).Length > 0 ||
                                args[i].StartsWith("-surname:") && args[i].Substring(9).Length > 0 ||
                                args[i].StartsWith("-patronymic:") && args[i].Substring(12).Length > 0 ||
                                args[i].StartsWith("-dob:") && args[i].Substring(5).Length > 0 &&
                               !args[i].StartsWith("-id:"))
                            {
                                valid = true;
                            }
                            else
                            {
                                return false;
                            }
                            if (args[i].StartsWith("-dob:"))
                            {
                                string dob = args[i].Substring(5);
                                DateTime dt;
                                if (!DateTime.TryParseExact(dob, "dd-MM-yyyy", null, DateTimeStyles.None, out dt))
                                {
                                    return false;
                                }
                            }
                        }
                    }
                }

                else if (args[0] == "-edit")
                {
                    if (CheckDuplicates(args))
                    {
                        return false;
                    }

                    if (args.Length >= 3 && args.Length <= 6 && args[1].StartsWith("-id:") && args[1].Length > 4)
                    {
                        if (TryParseID(args[1].Substring(4)))
                        {
                            for (int i = 2; i < args.Length; i++)
                            {
                                if (args[i].StartsWith("-name:") && args[i].Substring(6).Length > 0 ||
                                    args[i].StartsWith("-surname:") && args[i].Substring(9).Length > 0 ||
                                    args[i].StartsWith("-patronymic:") && args[i].Substring(12).Length > 0 ||
                                    args[i].StartsWith("-dob:") && args[i].Substring(5).Length > 0)
                                {
                                    valid = true;
                                }
                                else
                                {
                                    return false;
                                }
                                if (args[i].StartsWith("-dob:"))
                                {
                                    string dob = args[i].Substring(5);
                                    DateTime dt;
                                    if (!DateTime.TryParseExact(dob, "dd-MM-yyyy", null, DateTimeStyles.None, out dt))
                                    {
                                        return false;
                                    }
                                }
                            }
                        }
                    }
                }
                else if (args[0] == "-delete" && args.Length == 2 && args[1].StartsWith("-id:"))
                {
                    if (TryParseID(args[1].Substring(4)))
                    {
                        valid = true;
                    }
                }
                else if (args[0] == "-list" && args.Length == 1)
                {
                    valid = true;
                }
                else
                {
                    valid = false;
                }
            }
            return valid;
        }


        static bool CheckDuplicates(string[] args)
        {
            string[] ar = { "-name:", "-surname:", "-patronymic:", "-dob:" };
            string full = string.Concat(args);

            foreach (var el in ar)
            {
                if (full.IndexOf(el) != full.LastIndexOf(el))
                {
                    return true;
                }
            }
            return false;
        }


        static public void SetColumnWidth(string[] headLines)
        {
            char[] res = new char[80];

            int[] index = { 0, 9, 27, 48, 64 };
            int[] columnWidth = { 8, 17, 20, 15, 15 };
            int i = 0;
            while (i < headLines.Length)
            {
                headLines[i].CopyTo(0, res, index[i], Math.Min(columnWidth[i], headLines[i].Length));
                i++;
            }
            string headLineRes = string.Join("", res);
            Console.WriteLine(headLineRes);
            return;
        }

        static public void PrintPatients(ArrayList res)
        {
            int i = 0;
            while (i < res.Count)
            {
               string dobStr;
                Patient p = (Patient)res[i];
               if (p.dob == DateTime.MinValue)
                {
                    dobStr = "";
                }
                else
                {
                    dobStr = p.dob.ToString("dd-MM-yyyy");
                }
               SetColumnWidth(new string[] { p.id.ToString(), p.name, p.surname, p.patronymic, dobStr});
                i++;
            }
        }
    }
    }
